local arrayext = require("arrayext")

local Array = {}
Array.__cname = "util.Array"
Array.__index = function(self, key)
    if "number" == type(key) then
        return self:GetAt(key)
    end
    return Array[key]
end

local ClearTypeEnum = {
    Reset = nil,
    FillNil = 1,
    Keep = 2,
}
Array.ClearTypeEnum = ClearTypeEnum


function Array.new()
    local obj = {}
    setmetatable(obj, Array)
    obj:ctor()
    return obj
end

function Array:ctor()
    self.count = 0
    self.arr = {}
end

function Array:Clear(clearType)
    local count = self.count
    if count < 1 then return end

    if clearType == ClearTypeEnum.Reset then
        self.arr = {}
    elseif clearType == ClearTypeEnum.FillNil then
        local arr = self.arr
        for i=1,count do
            arr[i] = nil
        end
    end
    self.count = 0
end

function Array:GetCount()
    return self.count
end

function Array:Add(v)
    self.count = self.count + 1
    self.arr[self.count] = v
end

function Array:InsertAt(index, v)
    local count_1 = self.count + 1
    if index < 1 or index > count_1 then return end
    local count = self.count
    local arr = self.arr
    if index == count_1 then
        count = count + 1
        arr[count] = v
        self.count = count
    else
        for i=count,index,-1 do --往后移动
            arr[i+1] = arr[i]
        end
        arr[index] = v
        self.count = count + 1
    end
end

function Array:GetAt(index)
    if index < 1 or index > self.count then return nil end
    return self.arr[index]
end

function Array:GetLastAt(index)
    return self:GetAt(self.count - index + 1)
end

function Array:RemoveAt(index)
    local count = self.count
    if index < 1 or index > count then return false end

    local arr = self.arr
    local ret = arr[index]
    if index == count then
        arr[index] = nil
    else
        for i=index,count-1 do --往前移动
            arr[i] = arr[i+1]
        end
        arr[count] = nil
    end
    self.count = count - 1
    return true, ret
end

function Array:RemoveLastAt(index)
    self:RemoveAt(self.count - index + 1)
end

function Array:RemoveRange(index, count)
    local a_count = self.count
    if index < 1 or index > a_count then return false end
    local index2 = index + count

    local arr = self.arr
    if index2 > a_count then --删除尾部n个元素
        for i=index,a_count do
            arr[i] = nil
        end
        self.count = index - 1
    else
        local i = index
        for j=index2,a_count do --往前移动
            arr[i] = arr[j]
            i = i + 1
        end
        for j=i,a_count do --移掉的置为nil
            arr[j] = nil
        end
        self.count = a_count - count
    end
    return true
end

function Array:Remove(v)
    local index = self:IndexOf(v)
    if index > 0 then
        self:RemoveAt(index)
        return true
    end
    return false
end

function Array:Contains(v)
    return self:IndexOf(v) > 0
end

function Array:IndexOf(v)
    local count = self.count
    if count < 1 then return -1 end
    local arr = self.arr
    for i=1,count do
        if arr[i] == v then
            return i
        end
    end
    return -1
end

function Array:Find(matchFunc)
    local count = self.count
    if count < 1 then return -1, nil end
    local arr = self.arr
    for i=1,count do
        local item = arr[i]
        if matchFunc(i, item) then
            return i, item
        end
    end
    return -1, nil
end

function Array:LastIndexOf(v)
    local count = self.count
    if count < 1 then return -1 end
    local arr = self.arr
    for i=count,1,-1 do
        if arr[i] == v then
            return i
        end
    end
    return -1
end

function Array:FindLast(matchFunc)
    local count = self.count
    if count < 1 then return -1, nil end
    local arr = self.arr
    for i=count,1,-1 do
        local item = arr[i]
        if matchFunc(i, item) then
            return i, item
        end
    end
    return -1, nil
end

function Array:Sort(func)
    if self.count < 1 then return end
    table.sort(self.arr, func)
end

function Array:Reverse()
    local count = self.count
    if count < 2 then return end
    local arr = self.arr
    local i = 1
    local j = count
    while i < j do
        arrayext.Swap(arr, i, j)
        i = i + 1
        j = j - 1
    end
end

function Array:Shuffle()
    local count = self.count
    if count < 2 then return end
    local arr = self.arr
    for i=1,count do
        local r = math.random(count)
        local temp = arr[i]
        arr[i] = arr[r]
        arr[r] = temp
    end
end

function Array:__tostring()
    if 0 == self.count then return "" end
    local strTb = {}
    for i=1,self.count do
        table.insert(strTb, tostring(self.arr[i]))
    end
    return table.concat(strTb, ",")
end

function Array:GetIterator()
    --todo: 遍历期间发生modify报错
    local iteratorCur = 1
    local function iterator(tb, key)
        if iteratorCur > self.count then return nil end
        local k = iteratorCur
        iteratorCur = iteratorCur + 1
        return k, self.arr[k]
    end
    return iterator
end

function Array:IsReadOnly()
    return false
end

return Array
